﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace HR_MapEditor
{
    public partial class Form1 : Form
    {
        // SGP C# wrappers
        SGP.CSGP_Direct3D m_D3D = null;
        SGP.CSGP_TextureManager m_TM = null;

        // Game time
        float m_fTimer = 0;

        // FPS
        int m_nFPS = 60;
        int m_nFrames = 0;
        float m_fFPSTimer = 0.0f;

        //Asset IDs
        int m_nTileSetImgID = -1;
        
        //Map info
        int m_nMapHeight = 3;
        int m_nMapWidth = 3;

        //Tile set information
        Size m_TileSetSize = new Size(4, 4);
        int m_nTileSize = 64;
        Point m_SelectedTile = new Point(0, 0);
        Point[,] m_Map = new Point[3, 3];

        //Map information

       
        struct SpawnPoint
        {
           public int index;
            
           public List<Point> Waypoints;
        };

        struct Spawn
        {
            int enemyType;
            int quantity;

            //All wave times will be in whole seconds
            // i.e.  A duration of 1 will be 1000 miliseconds
            int duration;

            //How many seconds to wait after the wave begins to start spawning
            //	enemies
            int delay;


            //This determines which spawner this spawn will...spawn from.
            int spawnIndex;
        };

        struct Wave
        {
            //All wave times will be in whole seconds
            // i.e.  A duration of 1 will be 1000 miliseconds

            //When a wave's duration is up, no more enemies will be spawned
            //The player must manually start the next wave
            int duration;

            List<Spawn> SpawnList;
        };

        Point m_Base = new Point(-1, -1);
        List<SpawnPoint> m_lSpawnPoints;
        List<Wave> m_lWaves;


        // Application running flag property
        public bool Running
        {
            get;
            set;
        }

        public Form1()
        {
            InitializeComponent();
            this.Focus();

            // Change the Current Working Directory out of the 'bin\Debug\' or 'bin\Release\' folders
            string dir = System.IO.Directory.GetCurrentDirectory();
            int index = dir.LastIndexOf("bin\\Debug");
            if (index != -1)
                dir = dir.Remove(index);
            index = dir.LastIndexOf("bin\\Release");
            if (index != -1)
                dir = dir.Remove(index);

            System.IO.Directory.SetCurrentDirectory(dir);

            // Store the Current Working Directory in the text box
            textBox3.Text = System.IO.Directory.GetCurrentDirectory();

            Size n = new Size();
            n.Width = m_TileSetSize.Width * m_nTileSize;
            n.Height = m_TileSetSize.Height * m_nTileSize;

            panelTileSelect.AutoScrollMinSize = n;
            //panelTileSelect.MaximumSize = n;
            //panelTileSelect.MinimumSize = n;

            numericUpDownMapWidth.Value = m_nMapWidth;
            numericUpDownMapHeight.Value = m_nMapWidth;

            


        }

        ////////////////////////////////////////////////////////////////////////////////
        // Form1_FormClosing
        //	- triggered when the form is about to be closed (after the close button is clicked)
        //	- sets flag to tell main loop to quit
        ////////////////////////////////////////////////////////////////////////////////
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Running = false;
        }


        ////////////////////////////////////////////////////////////////////////////////
        // Form1_KeyDown
        //	- triggered when a key is first pressed
        //	- closes the application when Escape is down
        //	- moves game entity
        ////////////////////////////////////////////////////////////////////////////////
        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            // What key?
            switch (e.KeyCode)
            {
                case Keys.Escape:
                    this.Close();
                    break;

                //case Keys.Up:
                //    m_nTankPosY -= 32;
                //    m_nTankDirection = 0;
                //    break;

                //case Keys.Down:
                //    m_nTankPosY += 32;
                //    m_nTankDirection = 2;
                //    break;

                //case Keys.Left:
                //    m_nTankPosX -= 32;
                //    m_nTankDirection = 3;
                //    break;

                //case Keys.Right:
                //    m_nTankPosX += 32;
                //    m_nTankDirection = 1;
                //    break;
            }
        }


        ////////////////////////////////////////////////////////////////////////////////
        // Initialize
        //	- initialize the SGP wrappers
        //	- load assets
        ////////////////////////////////////////////////////////////////////////////////
        public void Initialize()
        {
            // Access the SGP Wrapper singletons
            m_D3D = SGP.CSGP_Direct3D.GetInstance();
            m_TM = SGP.CSGP_TextureManager.GetInstance();

            // Initialize the Direct3D render targets
            m_D3D.Initialize(panelMap, false);
            m_D3D.AddRenderTarget(panelTileSelect);

            // Initialize the Texture Manager
            m_TM.Initialize(m_D3D.Device, m_D3D.Sprite);

            // Load assets
            m_nTileSetImgID = m_TM.LoadTexture("resource/tiles.png");

            // Center the ship in the right panel
            //m_nShipPosX = (pnlRight.Width - 64) / 2;
            //m_nShipPosY = (pnlRight.Height - 64) / 2;

            // success.
            Running = true;
        }


        ////////////////////////////////////////////////////////////////////////////////
        // Terminate
        //	- unload assets
        //	- terminate the SGP wrappers
        ////////////////////////////////////////////////////////////////////////////////
        public void Terminate()
        {
            // Unload assets
           // if (m_nTileSetImgID != -1)
            //{
            //    m_TM.UnloadTexture(m_nTileSetImgID);
            //    m_nTileSetImgID = -1;
            //}

            // Shut down the wrappers
            m_TM.Terminate();
            m_D3D.Terminate();
        }

        ////////////////////////////////////////////////////////////////////////////////
        // Update
        //	- update timers & game entities
        ////////////////////////////////////////////////////////////////////////////////
        public void Update(float fElapsedTime)
        {
            // Update global timer
            m_fTimer += fElapsedTime;

            // Update FPS
            ++m_nFrames;
            m_fFPSTimer += fElapsedTime;
            if (m_fFPSTimer > 1.0f)	// refresh every second
            {
                m_nFPS = m_nFrames;
                m_nFrames = 0;
                m_fFPSTimer = 0.0f;
            }



            // Spin the ship
            //m_fShipRotation += (float)(Math.PI / 4) * fElapsedTime;
        }

        ////////////////////////////////////////////////////////////////////////////////
        // Render
        //	- render game entities
        ////////////////////////////////////////////////////////////////////////////////
        public void Render()
        {
            // Render both Direct3D panels
            RenderMap();
            
            //If not viewing the map editor
            if (tabControl2.SelectedTab != tabPage4)
                RenderTileSelect();

            // Draw the application time (in milliseconds with 2 precision) in the text box
            //txtTime.Text = ((int)(m_fTimer * 100) / 100.0f).ToString();

            // Draw the fps in the text box
            //txtFPS.Text = m_nFPS.ToString();
        }


        //Save to XML file
        private void toolStripMenuItem4_Click(object sender, EventArgs e)
        {

        }

        //Open the Tile Set Editor
        private void button2_Click(object sender, EventArgs e)
        {

        }



        //Change the directory of where to save the map
        private void textBox3_TextChanged(object sender, EventArgs e)
        {

        }

        //Place/replace the base
        private void button3_Click(object sender, EventArgs e)
        {
            m_Base = new Point(0, 0);
        }

        //Add new wave of enemies
        private void button8_Click(object sender, EventArgs e)
        {
            m_lWaves
        }

        //Change currently selected spawn point X value
        private void numericUpDown7_ValueChanged(object sender, EventArgs e)
        {

        }

        //Change currently selected spawn point X value
        private void numericUpDown4_ValueChanged(object sender, EventArgs e)
        {

        }

        //Move UP currently selected spawn point index value
        private void button7_Click(object sender, EventArgs e)
        {

        }

        //Move Down currently selected spawn point index value
        private void button5_Click(object sender, EventArgs e)
        {

        }

        //Move Up currently selected way point index value
        private void numericUpDown8_ValueChanged(object sender, EventArgs e)
        {

        }

        //Move Down currently selected way point index value
        private void numericUpDown9_ValueChanged(object sender, EventArgs e)
        {

        }

        //Delete currently Selected Spawn Point and connected waypoints
        private void button6_Click(object sender, EventArgs e)
        {

        }

        //Add new Spawn point
        private void button4_Click(object sender, EventArgs e)
        {

        }

        //Delete currently selected waypoint
        private void button12_Click(object sender, EventArgs e)
        {

        }

        //Add new waypoint to the spawn point
        private void button11_Click(object sender, EventArgs e)
        {

        }

        //Load from XML file
        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        //Render Map
        public void RenderMap()
        {
            // Clear the left render target
            m_D3D.Clear(panelMap, Color.White);
           

            // Begin rendering
            m_D3D.DeviceBegin();
            m_D3D.SpriteBegin();
            {
                //Render Background layer
                // Draw stuff
                //Rectangle drawTo = new Rectangle();


                // Tank's mini-map rect is 50% smaller than the image
                //drawTo.X        = 0;
                //drawTo.Y        = 0;
                //drawTo.Width    = 64;
                //drawTo.Height   = 64;


                //m_TM.Draw(m_nTileSetImgID, 0, 0, 1, 1, Rectangle.Empty, 0, 0, 0);

                //Render Interactivity Layer
                //if (tabControl2.SelectedTab == tabPage4)
                //{
                //    m_D3D.DrawRect(drawTo, Color.Black);
                //    m_D3D.DrawHollowRect(drawTo, Color.Blue, 3);
                //}



                // Line from one to the other
                //m_D3D.DrawLine((m_nTankPosX + 32) / 2, (m_nTankPosY + 32) / 2,
                //                (m_nShipPosX + 16) / 2, (m_nShipPosY + 16) / 2, Color.Black, 1);

                for (int x = 0; x < m_nMapWidth; x++)
                {
                    for (int y = 0; y < m_nMapHeight; y++)
                    {
                        DrawTile( GetID(m_Map[x,y]), x, y);
                    }
                }

            }
            // End rendering
            m_D3D.SpriteEnd();
            m_D3D.DeviceEnd();
            m_D3D.Present();
        }

        private void DrawTile(int id, int x, int y)
        {
            int tempX = id % m_TileSetSize.Width;
            int tempY = id / m_TileSetSize.Width;
            

            //Turn the x and y into pixel values, instead of cell locations
            x *= m_nTileSize;
            y *= m_nTileSize;

            //Offset the x and y according to the current auto scroll position
            x = x + panelMap.AutoScrollPosition.X;
            y = y + panelMap.AutoScrollPosition.Y;



            //Where to draw the tile
            Rectangle destRect = new Rectangle( x, y, m_nTileSize, m_nTileSize);

            //Which part of the image to draw from
            Rectangle srcRect = Rectangle.Empty;
            srcRect.X = tempX* m_nTileSize;
            srcRect.Y = tempY * m_nTileSize;
            srcRect.Size = new Size(m_nTileSize, m_nTileSize);

            m_TM.Draw(m_nTileSetImgID, x, y, 1, 1, srcRect);
        }

        //Render Tile Select
        public void RenderTileSelect()
        {
            // Clear the left render target
            m_D3D.Clear(panelTileSelect, Color.White);


            // Begin rendering
            m_D3D.DeviceBegin();
            m_D3D.SpriteBegin();
            {
                // Draw stuff
                Rectangle drawTo = new Rectangle();


                // Tank's mini-map rect is 50% smaller than the image
                drawTo.X = 0;
                drawTo.Y = 0;
                drawTo.Width = 64;
                drawTo.Height = 64;

                //m_D3D.DrawRect(drawTo, Color.Black);
                //m_D3D.DrawHollowRect(drawTo, Color.Blue, 3);

                //Offset the image to the scrollbar positions
                Point offset = new Point(0, 0);

                offset.X += panelTileSelect.AutoScrollPosition.X;
                offset.Y += panelTileSelect.AutoScrollPosition.Y;

                //Draw the tile map offset by the scrollbars
                m_TM.Draw(m_nTileSetImgID, offset.X, offset.Y, 1, 1, Rectangle.Empty, 0, 0, 0);
                
                //Draw the grid overlaying the text
                Rectangle overGrid = new Rectangle();
                overGrid.Size = new Size(m_nTileSize, m_nTileSize);
                Point here = new Point();

                for (int x = 0; x < m_TileSetSize.Width; ++x)
                {
                    for (int y = 0; y < m_TileSetSize.Height; ++y)
                    {
                        here.X = (x) * m_nTileSize + offset.X;
                        here.Y = (y) * m_nTileSize + offset.Y;
                        overGrid.Location = here;
                        m_D3D.DrawHollowRect(overGrid, Color.Black, 3);
                    }
                }

                //Draw a white grid around the currently selected tile
                Rectangle sel = new Rectangle();
                sel.Size = new Size(m_nTileSize, m_nTileSize);
                Point selloc = new Point();
                selloc.X = m_SelectedTile.X * m_nTileSize + panelTileSelect.AutoScrollPosition.X;
                selloc.Y = m_SelectedTile.Y * m_nTileSize + panelTileSelect.AutoScrollPosition.Y;
                sel.Location = selloc;
                m_D3D.DrawHollowRect(sel, Color.White, 4);




                // Line from one to the other
                //m_D3D.DrawLine((m_nTankPosX + 32) / 2, (m_nTankPosY + 32) / 2,
                //                (m_nShipPosX + 16) / 2, (m_nShipPosY + 16) / 2, Color.Black, 1);
            }
            // End rendering
            m_D3D.SpriteEnd();
            m_D3D.DeviceEnd();
            m_D3D.Present();
        }

        private void numericUpDownMapWidth_ValueChanged(object sender, EventArgs e)
        {
            Point[,] p = new Point[(int)numericUpDownMapWidth.Value, m_nMapHeight];


            if (m_nMapWidth > numericUpDownMapWidth.Value)//if you made the map thinner...
            {
                for (int i = 0; i < numericUpDownMapWidth.Value; i++)
                {
                    for (int j = 0; j < m_nMapHeight; j++)
                    {
                        p[i, j] = m_Map[i, j];
                    }
                }
            }
            else//if you made the map fatter
            {

                for (int i = 0; i < m_nMapWidth; i++)
                {
                    for (int j = 0; j < m_nMapHeight; j++)
                    {
                        p[i, j] = m_Map[i, j];
                    }
                }
            }
            m_Map= p;
            m_nMapWidth = (int)numericUpDownMapWidth.Value;
            Size t = new Size(m_nTileSize * m_nMapWidth, m_nTileSize * m_nMapHeight);
            //splitContainer1.Panel2.AutoScrollMinSize = t;
            //splitContainer1.Panel2.Invalidate();

            panelMap.AutoScrollMinSize = t;

            //panelMap.Invalidate();
        }

        private void panelTileSelect_MouseClick(object sender, MouseEventArgs e)
        {
            int x = (e.X - panelTileSelect.AutoScrollPosition.X) / (m_nTileSize);
            int y = (e.Y - panelTileSelect.AutoScrollPosition.Y) / (m_nTileSize);
            m_SelectedTile = new Point(x, y);

            if (x < m_nMapWidth && y < m_nMapHeight)
            {

                //m_Map[x, y] = m_SelectedTile;
            }

           panelTileSelect.Invalidate();
        }

        private void panelMap_MouseClick(object sender, MouseEventArgs e)
        {
            int x = (e.X - panelMap.AutoScrollPosition.X) / (m_nTileSize);
            int y = (e.Y - panelMap.AutoScrollPosition.Y) / (m_nTileSize);

            if (x < m_nMapWidth && y < m_nMapHeight)
                m_Map[x, y] = m_SelectedTile;

            panelMap.Invalidate();
        }

        //Drag to paint
        private void panelMap_MouseMove(object sender, MouseEventArgs e)
        {
            Point p = e.Location;
            p.X -= panelMap.AutoScrollPosition.X;
            p.Y -= panelMap.AutoScrollPosition.Y;

            if (e.Button == MouseButtons.Left)
            {
                int x = (e.X - panelMap.AutoScrollPosition.X) / (m_nTileSize);
                int y = (e.Y - panelMap.AutoScrollPosition.Y) / (m_nTileSize);

                if (x < m_nMapWidth && y < m_nMapHeight)
                    m_Map[x, y] = m_SelectedTile;

                //splitContainer1.Panel2.Invalidate();
            }

        }

        private void panelTileSelect_Scroll(object sender, ScrollEventArgs e)
        {
            //panelTileSelect.Invalidate();
        }

        //turns a coordinate into a tile ID
        private int GetID(Point p)
        {
            int id;
            id = p.Y * m_TileSetSize.Width + p.X;

            return id;

        }

        //Dynamic resizing map height
        private void numericUpDownMapHeight_ValueChanged(object sender, EventArgs e)
        {
            //This allows for dynamic resizing of the map!
            Point[,] p = new Point[m_nMapWidth, (int)numericUpDownMapHeight.Value];

            if (m_nMapHeight > numericUpDownMapHeight.Value)//if you made the map shorter...
            {
                for (int i = 0; i < m_nMapWidth; i++)
                {
                    for (int j = 0; j < numericUpDownMapHeight.Value; j++)
                    {
                        p[i, j] = m_Map[i, j];
                    }
                }
            }
            else//if you made the map taller
            {

                for (int i = 0; i < m_nMapWidth; i++)
                {
                    for (int j = 0; j < m_nMapHeight; j++)
                    {
                        p[i, j] = m_Map[i, j];
                    }
                }
            }
            m_Map = p;

            m_nMapHeight = (int)numericUpDownMapHeight.Value;
            Size t = new Size(m_nTileSize * m_nMapWidth, m_nTileSize* m_nMapHeight);
            panelMap.AutoScrollMinSize = t;
            //panelMap.Invalidate();

        }

        

        ////////////////////////////////////////////////////////////////////////////////
        // RenderLeft
        //	- render the left panel
        ////////////////////////////////////////////////////////////////////////////////
        //public void RenderLeft()
        //{
        //    // Clear the left render target
        //    m_D3D.Clear(pnlLeft, Color.DarkGreen);

        //    // Begin rendering
        //    m_D3D.DeviceBegin();
        //    m_D3D.SpriteBegin();
        //    {
        //        // Draw stuff
        //        Rectangle rect = new Rectangle();


        //        // Tank's mini-map rect is 50% smaller than the image
        //        rect.X = m_nTankPosX / 2;
        //        rect.Y = m_nTankPosY / 2;
        //        rect.Width = 64 / 2;
        //        rect.Height = 64 / 2;

        //        m_D3D.DrawRect(rect, Color.Blue);
        //        m_D3D.DrawHollowRect(rect, Color.White, 3);


        //        // Ship's image is scaled to 50%, and the mini-map is another 50% smaller
        //        rect = new Rectangle(m_nShipPosX / 2, m_nShipPosY / 2, 64 / 4, 64 / 4);
        //        m_D3D.DrawHollowRect(rect, Color.White, 3);
        //        m_D3D.DrawRect(rect, Color.Red);


        //        // Line from one to the other
        //        m_D3D.DrawLine((m_nTankPosX + 32) / 2, (m_nTankPosY + 32) / 2,
        //                        (m_nShipPosX + 16) / 2, (m_nShipPosY + 16) / 2, Color.Black, 1);
        //    }
        //    // End rendering
        //    m_D3D.SpriteEnd();
        //    m_D3D.DeviceEnd();
        //    m_D3D.Present();
        //}

		////////////////////////////////////////////////////////////////////////////////
		// RenderRight
		//	- render the right panel
		////////////////////////////////////////////////////////////////////////////////
        //public void RenderRight( )
        //{
        //    // Clear the right render target
        //    m_D3D.Clear( pnlRight, Color.FromArgb( 255, 0, 0, 0 ) );

        //    // Begin rendering
        //    m_D3D.DeviceBegin( );
        //    m_D3D.SpriteBegin( );
        //    {
        //        // Draw the tank image
        //        if( m_nTankID != -1 )
        //        {
        //            m_TM.Draw( m_nTankID, m_nTankPosX, m_nTankPosY, 1.0f, 1.0f, Rectangle.Empty, 32.0f, 32.0f, (float)(m_nTankDirection * Math.PI / 2) );
        //        }

        //        // Draw the ship image
        //        if( m_nShipID != -1 )
        //        {
        //            Rectangle rect = new Rectangle( );
        //            rect.X = 0;
        //            rect.Y = 0;
        //            rect.Width = 64;
        //            rect.Height = 64;
        //            m_TM.Draw( m_nShipID, m_nShipPosX, m_nShipPosY, 0.5f, 0.5f, rect, 16.0f, 16.0f, m_fShipRotation );

        //            rect.Offset( +64, 0 );
        //            m_TM.Draw( m_nShipID, m_nShipPosX, m_nShipPosY, 0.5f, 0.5f, rect, 16.0f, 16.0f, m_fShipRotation, Color.FromArgb( 255, 255, 128, 0 ) );
        //        }


        //        // Line from one to the other
        //        m_D3D.DrawLine( m_nTankPosX + 32, m_nTankPosY + 32, m_nShipPosX + 16, m_nShipPosY + 16, Color.FromArgb( 255, 255, 255, 255 ), 3 );
				
        //    }
        //    // End rendering
        //    m_D3D.SpriteEnd( );
        //    m_D3D.DeviceEnd( );
        //    m_D3D.Present( );
        //}

    }
}
